Bounding box avec BiomedParse

Ce Notebook tente d'utiliser BiomedParse pour la création de bounding box à fournir à un autre agent de segmentation type MedSAM.

In [12]:
import G_inferenceCall as call
import pandas as pd

model = call.getModel()
➡️  Type de tokenizer : clip
➡️  Chemin/tokenizer utilisé : ./local-tokenizer/clip-vit-base-patch32
➡️  Contenu complet config_encoder : {'ARCH': 'vlpencoder', 'NAME': 'transformer', 'TOKENIZER': 'clip', 'PRETRAINED_TOKENIZER': './local-tokenizer/clip-vit-base-patch32', 'CONTEXT_LENGTH': 77, 'WIDTH': 512, 'HEADS': 8, 'LAYERS': 12, 'AUTOGRESSIVE': True}
✅ Tokenizer FINAL utilisé: ./local-tokenizer/clip-vit-base-patch32
In [13]:
import random as rd 

# patient = rd.randint(0,66)
patient = 42
print(patient)
masks = call.showInference(patient, model)
42
0
No description has been provided for this image
1
No description has been provided for this image
2
No description has been provided for this image
3
No description has been provided for this image
4
No description has been provided for this image
5
No description has been provided for this image
6
No description has been provided for this image
7
No description has been provided for this image
8
No description has been provided for this image
9
No description has been provided for this image
10
No description has been provided for this image
11
No description has been provided for this image
12
No description has been provided for this image
13
No description has been provided for this image
14
No description has been provided for this image
15
No description has been provided for this image
16
No description has been provided for this image
17
No description has been provided for this image
18
No description has been provided for this image
19
No description has been provided for this image
20
No description has been provided for this image
21
No description has been provided for this image
22
No description has been provided for this image
23
No description has been provided for this image
24
No description has been provided for this image
25
No description has been provided for this image
26
No description has been provided for this image
27
No description has been provided for this image
28
No description has been provided for this image
29
No description has been provided for this image
30
No description has been provided for this image
31
No description has been provided for this image
32
No description has been provided for this image
33
No description has been provided for this image
34
No description has been provided for this image
35
No description has been provided for this image
36
No description has been provided for this image
37
No description has been provided for this image
38
No description has been provided for this image
39
No description has been provided for this image
40
No description has been provided for this image
41
No description has been provided for this image
42
No description has been provided for this image
43
No description has been provided for this image
In [14]:
import numpy as np

segMasks = []

for i in range(len(masks)):
    binary_mask = (masks[i][1] > 0.5).astype(np.uint8)
    segMasks.append(binary_mask)
In [15]:
weightedMask = np.sum(segMasks, axis=0) / len(segMasks)
In [16]:
import matplotlib.pyplot as plt

plt.imshow(weightedMask, cmap='hot')
plt.colorbar(label='Nombre de masques actifs')
plt.title('Weighted Mask - Heatmap')
plt.axis('off') 
plt.show()
No description has been provided for this image

On calcule les coordonnées du barycentre de la façon suivante :

$$ \bar{x} = \frac{\sum_{i=0}^{H-1} \sum_{j=0}^{W-1} j \cdot \text{weightedMask}[i][j]}{\sum_{i=0}^{H-1} \sum_{j=0}^{W-1} \text{weightedMask}[i][j]} $$

$$ \bar{y} = \frac{\sum_{i=0}^{H-1} \sum_{j=0}^{W-1} i \cdot \text{weightedMask}[i][j]}{\sum_{i=0}^{H-1} \sum_{j=0}^{W-1} \text{weightedMask}[i][j]} $$

In [17]:
xb, yb = 0, 0

for i in range(len(weightedMask)):
    for j in range(len(weightedMask[0])):
        xb += weightedMask[i][j] * j
        yb += weightedMask[i][j] * i

xb = xb / np.sum(weightedMask)
yb = yb / np.sum(weightedMask)
In [18]:
plt.scatter(xb, yb, c = 'blue')
plt.imshow(weightedMask, cmap='hot')
plt.colorbar(label='Nombre de masques actifs')
plt.title('Weighted Mask - barycentre en bleu')
plt.axis('off') 
plt.show()
No description has been provided for this image

On cherche maintenant un rectangle dont le centre est le barycentre qu'on vient de trouver, tel que la plus part des pixels "importants" sont à l'interieur.

In [19]:
strong = (weightedMask > np.max(weightedMask)/10).astype(np.uint8) 
plt.scatter(xb, yb, c = 'blue')
plt.imshow(strong, cmap='hot')
plt.colorbar(label='Nombre de masques actifs')
plt.axis('off') 
plt.show()
No description has been provided for this image
    +---------------------------+
    |      |                    |
    |      |y1                  |
    |      |                    |
    |  x1  |        x2          |
    |------*--------------------|
    |      |y2                  |
    +---------------------------+

Le rectangle contient tous les pixel de strong.

In [20]:
limx = int(np.minimum(len(weightedMask) - xb, xb))
limy = int(np.minimum(len(weightedMask) - yb, yb))
intxb, intyb = int(xb), int(yb)
# x1
x1 = 0
for p in range(limx):
    lst = []
    for y in range(len(strong)):
        if strong[y][intxb-p] == 1:
            lst.append((y, xb-p))
    if len(lst) == 0:
        x1 = xb-p
        break 

# x2
x2 = 0
for p in range(limx):
    lst = []
    for y in range(len(strong)):
        if strong[y][intxb+p] == 1:
            lst.append((y, xb-p))
    if len(lst) == 0:
        x2 = xb+p
        break 

# y1
y1 = 0
for p in range(limy):
    lst = []
    for x in range(len(strong[0])):
        if strong[intyb-p][x] == 1:
            lst.append((intyb, x))
    if len(lst) == 0:
        y1 = yb-p
        break 

# y2
y2 = 0
for p in range(limy):
    lst = []
    for x in range(len(strong[0])):
        if strong[intyb+p][x] == 1:
            lst.append((intyb, x))
    if len(lst) == 0:
        y2 = yb+p
        break 
    
In [21]:
plt.plot([x1,x1], [y1, y2])
plt.plot([x2,x2], [y2, y1])
plt.plot([x1,x2], [y1, y1])
plt.plot([x2,x1], [y2, y2])
plt.imshow(strong, cmap='hot')
plt.colorbar(label='Nombre de masques actifs')
plt.title('Weighted Mask - barycentre en bleu')
plt.axis('off') 
plt.show()
No description has been provided for this image
In [ ]:
# x1 = x1 / 1.1
# x2 = x2 * 1.1
# y1 = y1 / 1.1
# y2 = y2 * 1.1

# On recentre la bounding box sur le barycentre
# dx = xb - (x1 + x2) / 2
# dy = yb - (y1 + y2) / 2

# x1 += dx
# x2 += dx
# y1 += dy
# y2 += dy

# Tracé du rectangle
plt.plot([x1,x1], [y1, y2])
plt.plot([x2,x2], [y2, y1])
plt.plot([x1,x2], [y1, y1])
plt.plot([x2,x1], [y2, y2])
plt.imshow(weightedMask, cmap='hot')
plt.colorbar(label='Nombre de masques actifs')
plt.title('Weighted Mask - barycentre en bleu')
plt.axis('off') 
plt.show()
No description has been provided for this image
In [66]:
import G_inferenceCall as call
vect = (x1, x2, y1, y2)
call.showBoundingBox(patient, model, vect)
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
Out[66]:
[[array([[-1024, -1024, -1024, ..., -1024, -1024, -1024],
         [-1024, -1024, -1024, ..., -1024, -1024, -1024],
         [-1024, -1024, -1024, ..., -1024, -1024, -1024],
         ...,
         [-1024, -1024, -1024, ..., -1024, -1024, -1024],
         [-1024, -1024, -1024, ..., -1024, -1024, -1024],
         [-1024, -1024, -1024, ..., -1024, -1024, -1024]], dtype=int16),
  array([[1.80621740e-10, 2.45798902e-11, 8.42984807e-15, ...,
          1.09843146e-23, 2.12638422e-19, 3.48974213e-16],
         [3.02733116e-11, 3.21108981e-12, 4.06462021e-16, ...,
          1.26294548e-25, 1.04097182e-20, 5.06382832e-17],
         [2.38902289e-14, 9.35279593e-16, 2.19697111e-21, ...,
          2.20712160e-33, 5.97899189e-26, 2.24504315e-20],
         ...,
         [3.38335595e-23, 2.87453716e-25, 1.49777220e-33, ...,
          0.00000000e+00, 2.63356983e-33, 6.61160595e-26],
         [8.36059207e-19, 2.49115797e-20, 1.96361593e-26, ...,
          5.08989008e-34, 1.33497406e-26, 4.89269214e-21],
         [1.64779714e-15, 1.25827724e-16, 4.27822296e-21, ...,
          3.72465183e-27, 1.42615389e-21, 2.19521625e-17]], dtype=float32)],
 [array([[-1024, -1024, -1024, ..., -1024, -1024, -1024],
         [-1024, -1024, -1024, ..., -1024, -1024, -1024],
         [-1024, -1024, -1024, ..., -1024, -1024, -1024],
         ...,
         [-1024, -1024, -1024, ..., -1024, -1024, -1024],
         [-1024, -1024, -1024, ..., -1024, -1024, -1024],
         [-1024, -1024, -1024, ..., -1024, -1024, -1024]], dtype=int16),
  array([[1.51336685e-08, 3.23294169e-09, 6.73306029e-12, ...,
          3.00534900e-18, 3.66734858e-15, 7.57170964e-13],
         [3.93526856e-09, 7.11461612e-10, 7.60082318e-13, ...,
          1.22659330e-19, 4.00400177e-16, 1.72916884e-13],
         [1.79925710e-11, 1.66864851e-12, 1.23438707e-16, ...,
          3.40350734e-25, 5.68932434e-20, 4.70338337e-16],
         ...,
         [3.10467850e-18, 8.75366921e-20, 5.53208986e-26, ...,
          1.43577415e-33, 2.32032511e-26, 5.91419840e-21],
         [6.05425989e-15, 3.88426228e-16, 6.58120001e-21, ...,
          4.33171265e-27, 1.82249982e-21, 3.01075512e-17],
         [1.77661260e-12, 2.11177565e-13, 4.21568132e-17, ...,
          3.13573750e-22, 8.55080174e-18, 1.81450432e-14]], dtype=float32)],
 [array([[-1024, -1024, -1024, ..., -1024, -1024, -1024],
         [-1024, -1024, -1024, ..., -1024, -1024, -1024],
         [-1024, -1024, -1024, ..., -1024, -1024, -1024],
         ...,
         [-1024, -1024, -1024, ..., -1024, -1024, -1024],
         [-1024, -1024, -1024, ..., -1024, -1024, -1024],
         [-1024, -1024, -1024, ..., -1024, -1024, -1024]], dtype=int16),
  array([[6.7913067e-12, 7.0300140e-13, 8.0717184e-17, ..., 1.9431030e-25,
          4.6840902e-20, 5.0959207e-16],
         [7.5760291e-13, 5.8177984e-14, 2.0231448e-18, ..., 7.1123120e-28,
          9.8307114e-22, 3.9629413e-17],
         [1.1732638e-16, 2.7287921e-18, 7.9848945e-25, ..., 1.2766507e-37,
          1.9073353e-28, 1.4494141
... [truncated for display only] ...

Test sur tous les patients¶

In [1]:
import G_inferenceCall as call
import pandas as pd
import numpy as np
import os

model = call.getModel()
Deformable Transformer Encoder is not available.
➡️  Type de tokenizer : clip
➡️  Chemin/tokenizer utilisé : ./local-tokenizer/clip-vit-base-patch32
➡️  Contenu complet config_encoder : {'ARCH': 'vlpencoder', 'NAME': 'transformer', 'TOKENIZER': 'clip', 'PRETRAINED_TOKENIZER': './local-tokenizer/clip-vit-base-patch32', 'CONTEXT_LENGTH': 77, 'WIDTH': 512, 'HEADS': 8, 'LAYERS': 12, 'AUTOGRESSIVE': True}
✅ Tokenizer FINAL utilisé: ./local-tokenizer/clip-vit-base-patch32
In [2]:
# TODO : ajouter une focntion pour filtrer les masques 


# on utilise getMask pour récupérer tous les mask gt et toutes les prédictions
# puis on fait tourner le code pour obtenir une bounding box pour chaque masque
# on regarde en moyenne la proportion du gt contenu dans la bounding box
masks = call.getMasks(model)
    
        
In [29]:
# masks = predicted_masks, ground_truth_masks
# print(len(masks[0][0]) == len(os.listdir('test/dcm/0/0/'))) => True 
import matplotlib.pyplot as plt

def isInBB(bb,coord):
    x1,x2,y1,y2 = bb 
    l,c = coord

    if l > y1 and c > x1 and c < x2 and l < y2 :
        return True
    
    return False

prop = []
propOk = []
z = []
for i in range(len(masks[0])):
    segMasks = []

    for j in range(len(masks[0][i])):
        binary_mask = (masks[0][i][j] > 0.5).astype(np.uint8)
        segMasks.append(binary_mask)

    weightedMask = np.sum(segMasks, axis=0) / len(segMasks)
    
    xb, yb = 0, 0

    for k in range(len(weightedMask)):
        for j in range(len(weightedMask[0])):
            xb += weightedMask[k][j] * j
            yb += weightedMask[k][j] * k

    xb = xb / np.sum(weightedMask)
    yb = yb / np.sum(weightedMask)

    strong = (weightedMask > np.max(weightedMask)/10).astype(np.uint8) 

    limx = int(np.minimum(len(weightedMask) - xb, xb))
    limy = int(np.minimum(len(weightedMask) - yb, yb))
    intxb, intyb = int(xb), int(yb)

    # x1
    x1 = 0
    for p in range(limx):
        lst = []
        for y in range(len(strong)):
            if strong[y][intxb-p] == 1:
                lst.append((y, xb-p))
        if len(lst) == 0:
            x1 = xb-p
            break 

    # x2
    x2 = 0
    for p in range(limx):
        lst = []
        for y in range(len(strong)):
            if strong[y][intxb+p] == 1:
                lst.append((y, xb-p))
        if len(lst) == 0:
            x2 = xb+p
            break 

    # y1
    y1 = 0
    for p in range(limy):
        lst = []
        for x in range(len(strong[0])):
            if strong[intyb-p][x] == 1:
                lst.append((intyb, x))
        if len(lst) == 0:
            y1 = yb-p
            break 

    # y2
    y2 = 0
    for p in range(limy):
        lst = []
        for x in range(len(strong[0])):
            if strong[intyb+p][x] == 1:
                lst.append((intyb, x))
        if len(lst) == 0:
            y2 = yb+p
            break 

    dx = xb - (x1 + x2) / 2
    dy = yb - (y1 + y2) / 2

    # x1 += dx
    # x2 += dx
    # y1 += dy
    # y2 += dy

    bb = x1,x2,y1,y2

    # on a obtenu la BoundingBox. On va maintenant parcourir tous les pixels de tous les masques gt et vérifier s'ils sont dans la BB.
    # on va calculer la proportion de pixel dans la bounding box et faire une moyenne par patient et on affichera le résultat avec un box plot.

    propPat = []
    propPatOk = []
    for j in range(len(masks[1][i])) :
        # print(len(masks[1][i][0]))
        # print(f"{j} : {masks[1][i][j]}")
        maskGt = masks[1][i][j]
        tot = 0
        c = 0
        for y in range(len(maskGt)):
            for x in range(len(maskGt[0])):
                if maskGt[y][x] == 1 :
                    tot+=1
                    if isInBB(bb, (y,x)) :
                        c+=1
        if tot == 0:
            tot=1
        pp = c/tot
        if pp == 0:
            z.append(pp)
        else:
            propPatOk.append(pp)
        propPat.append(pp)
    prop.append(np.mean(propPat))
    if propPatOk : propOk.append(np.mean(propPatOk))
print(f"Nombre de cas où ça n'a pas du tout fonctionné : {len(z)}")
print(f"Proportion d'anglobement moyen par patient pour les autre cas : {np.mean(propOk)}")
print(f"Proportion d'anglobement moyen : {np.mean(prop)}")
plt.figure(figsize=(10, 6))
plt.boxplot([prop, propOk], labels=['Tous les cas', 'Cas réussis (>0)'])
plt.ylabel("Proportion d'engloberment")
plt.title("Boxplot des proportions d'engloberment par patient")
plt.grid(True)
plt.show()

        
        
Nombre de cas où ça n'a pas du tout fonctionné : 482
Proportion d'anglobement moyen par patient pour les autre cas : 0.8777389413907586
Proportion d'anglobement moyen : 0.5957957394628821
No description has been provided for this image
In [ ]:
print(len(masks[0]))
c=0
for i in range(len(masks[0])):
    c+=len(masks[0][i])
print(c)
482/1261 * 100
63
1261
Out[ ]:
38.22363203806503

Filtrage des masques¶

In [1]:
import G_inferenceCall as call
import pandas as pd
import random as rd 

model = call.getModel()
Deformable Transformer Encoder is not available.
➡️  Type de tokenizer : clip
➡️  Chemin/tokenizer utilisé : ./local-tokenizer/clip-vit-base-patch32
➡️  Contenu complet config_encoder : {'ARCH': 'vlpencoder', 'NAME': 'transformer', 'TOKENIZER': 'clip', 'PRETRAINED_TOKENIZER': './local-tokenizer/clip-vit-base-patch32', 'CONTEXT_LENGTH': 77, 'WIDTH': 512, 'HEADS': 8, 'LAYERS': 12, 'AUTOGRESSIVE': True}
✅ Tokenizer FINAL utilisé: ./local-tokenizer/clip-vit-base-patch32
In [9]:
patient = rd.randint(0,66)
print(patient)


print("Filtré :")
masks = call.showFilteredInference(patient, model)
10
Filtré :
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
In [12]:
import numpy as np
import matplotlib.pyplot as plt

segMasks = []

for i in range(len(masks)):
    binary_mask = (masks[i][1] > 0.5).astype(np.uint8)
    segMasks.append(binary_mask)

weightedMask = np.sum(segMasks, axis=0) / len(segMasks)

xb, yb = 0, 0

for i in range(len(weightedMask)):
    for j in range(len(weightedMask[0])):
        xb += weightedMask[i][j] * j
        yb += weightedMask[i][j] * i

xb = xb / np.sum(weightedMask)
yb = yb / np.sum(weightedMask)

strong = (weightedMask > np.max(weightedMask)/10).astype(np.uint8) 

limx = int(np.minimum(len(weightedMask) - xb, xb))
limy = int(np.minimum(len(weightedMask) - yb, yb))
intxb, intyb = int(xb), int(yb)
# x1
x1 = 0
for p in range(limx):
    lst = []
    for y in range(len(strong)):
        if strong[y][intxb-p] == 1:
            lst.append((y, xb-p))
    if len(lst) == 0:
        x1 = xb-p
        break 

# x2
x2 = 0
for p in range(limx):
    lst = []
    for y in range(len(strong)):
        if strong[y][intxb+p] == 1:
            lst.append((y, xb-p))
    if len(lst) == 0:
        x2 = xb+p
        break 

# y1
y1 = 0
for p in range(limy):
    lst = []
    for x in range(len(strong[0])):
        if strong[intyb-p][x] == 1:
            lst.append((intyb, x))
    if len(lst) == 0:
        y1 = yb-p
        break 

# y2
y2 = 0
for p in range(limy):
    lst = []
    for x in range(len(strong[0])):
        if strong[intyb+p][x] == 1:
            lst.append((intyb, x))
    if len(lst) == 0:
        y2 = yb+p
        break 

# dx = xb - (x1 + x2) / 2
# dy = yb - (y1 + y2) / 2

# x1 += dx
# x2 += dx
# y1 += dy
# y2 += dy

vect = (x1, x2, y1, y2)

call.showBoundingBox(patient, model, vect)
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
Out[12]:
[[array([[-1024, -1024, -1024, ..., -1024, -1024, -1024],
         [-1024, -1024, -1024, ..., -1024, -1024, -1024],
         [-1024, -1024, -1024, ..., -1024, -1024, -1024],
         ...,
         [-1024, -1024, -1024, ..., -1024, -1024, -1024],
         [-1024, -1024, -1024, ..., -1024, -1024, -1024],
         [-1024, -1024, -1024, ..., -1024, -1024, -1024]], dtype=int16),
  array([[1.97989635e-07, 4.69208565e-08, 1.47998974e-10, ...,
          3.03989669e-16, 1.21900306e-13, 1.09235425e-11],
         [5.77473216e-08, 1.19963133e-08, 2.23413926e-11, ...,
          1.98766604e-17, 1.81984876e-14, 3.02903340e-12],
         [4.17917340e-10, 5.12596840e-11, 1.16015367e-14, ...,
          3.63310938e-22, 9.03975316e-18, 1.79087973e-14],
         ...,
         [3.25262536e-15, 1.57040186e-16, 8.53331920e-22, ...,
          3.55431796e-27, 1.35503857e-21, 2.07897570e-17],
         [1.83802171e-12, 1.91848179e-13, 2.27712384e-17, ...,
          8.90767093e-22, 1.29345819e-17, 1.71096962e-14],
         [2.13028289e-10, 3.96430631e-11, 4.75431225e-14, ...,
          9.97747075e-18, 1.24911525e-14, 2.62899056e-12]], dtype=float32)],
 [array([[-1024, -1024, -1024, ..., -1024, -1024, -1024],
         [-1024, -1024, -1024, ..., -1024, -1024, -1024],
         [-1024, -1024, -1024, ..., -1024, -1024, -1024],
         ...,
         [-1024, -1024, -1024, ..., -1024, -1024, -1024],
         [-1024, -1024, -1024, ..., -1024, -1024, -1024],
         [-1024, -1024, -1024, ..., -1024, -1024, -1024]], dtype=int16),
  array([[4.2757144e-08, 9.3476578e-09, 2.1354076e-11, ..., 1.9738313e-17,
          7.6622990e-15, 6.7010785e-13],
         [1.1860260e-08, 2.2817808e-09, 3.1260259e-12, ..., 1.3326137e-18,
          1.2015321e-15, 1.9770001e-13],
         [7.0216194e-11, 8.1013538e-12, 1.4356175e-15, ..., 2.7687450e-23,
          7.2650555e-19, 1.4977971e-15],
         ...,
         [8.6443476e-16, 4.1258558e-17, 2.1411462e-22, ..., 1.3816863e-27,
          6.6817246e-22, 1.2253179e-17],
         [4.1913803e-13, 4.4248761e-14, 5.4963740e-18, ..., 3.4279694e-22,
          5.5703141e-18, 8.0169822e-15],
         [4.3308804e-11, 8.2926010e-12, 1.1146750e-14, ..., 3.8107289e-18,
          4.8598380e-15, 1.0371273e-12]], dtype=float32)],
 [array([[-1024, -1024, -1024, ..., -1024, -1024, -1024],
         [-1024, -1024, -1024, ..., -1024, -1024, -1024],
         [-1024, -1024, -1024, ..., -1024, -1024, -1024],
         ...,
         [-1024, -1024, -1024, ..., -1024, -1024, -1024],
         [-1024, -1024, -1024, ..., -1024, -1024, -1024],
         [-1024, -1024, -1024, ..., -1024, -1024, -1024]], dtype=int16),
  array([[2.9726408e-07, 7.6548908e-08, 3.3660824e-10, ..., 2.8782590e-16,
          9.5963568e-14, 7.4875271e-12],
         [9.4566943e-08, 2.1683647e-08, 5.9938242e-11, ..., 2.1719847e-17,
          1.4964245e-14, 2.0123480e-12],
         [9.6855979e-10, 1.3960616e-10, 6.0258649e-14, ..., 7.0431077e-22,
          8.8480838e-18, 1.0499362e-14],
         ...,
         [1.971
... [truncated for display only] ...

Évaluation sur tous les patients¶

In [1]:
import G_inferenceCall as call
import pandas as pd
import numpy as np
import os

model = call.getModel()
Deformable Transformer Encoder is not available.
➡️  Type de tokenizer : clip
➡️  Chemin/tokenizer utilisé : ./local-tokenizer/clip-vit-base-patch32
➡️  Contenu complet config_encoder : {'ARCH': 'vlpencoder', 'NAME': 'transformer', 'TOKENIZER': 'clip', 'PRETRAINED_TOKENIZER': './local-tokenizer/clip-vit-base-patch32', 'CONTEXT_LENGTH': 77, 'WIDTH': 512, 'HEADS': 8, 'LAYERS': 12, 'AUTOGRESSIVE': True}
✅ Tokenizer FINAL utilisé: ./local-tokenizer/clip-vit-base-patch32
In [ ]:
#masks = call.getMasks(model)
In [ ]:
# np.save("masks.npy", np.array(masks, dtype=object), allow_pickle=True)
In [2]:
masks = np.load("masks.npy", allow_pickle=True)
In [3]:
# masks = predicted_masks, ground_truth_masks
# print(len(masks[0][0]) == len(os.listdir('test/dcm/0/0/'))) => True 
import matplotlib.pyplot as plt

def isInBB(bb,coord):
    x1,x2,y1,y2 = bb 
    l,c = coord

    if l > y1 and c > x1 and c < x2 and l < y2 :
        return True
    
    return False

prop = []
propOk = []
z = []
for i in range(len(masks[0])):

    fltMasks = call.maskFilter(masks[0][i])
    
    segMasks = []

    for j in range(len(fltMasks)):
        binary_mask = (fltMasks[j] > 0.5).astype(np.uint8)
        segMasks.append(binary_mask)

    weightedMask = np.sum(segMasks, axis=0) / len(segMasks)
    
    xb, yb = 0, 0

    for k in range(len(weightedMask)):
        for j in range(len(weightedMask[0])):
            xb += weightedMask[k][j] * j
            yb += weightedMask[k][j] * k

    xb = xb / np.sum(weightedMask)
    yb = yb / np.sum(weightedMask)

    strong = (weightedMask > np.max(weightedMask)/10).astype(np.uint8) 

    limx = int(np.minimum(len(weightedMask) - xb, xb))
    limy = int(np.minimum(len(weightedMask) - yb, yb))
    intxb, intyb = int(xb), int(yb)

    # x1
    x1 = 0
    for p in range(limx):
        lst = []
        for y in range(len(strong)):
            if strong[y][intxb-p] == 1:
                lst.append((y, xb-p))
        if len(lst) == 0:
            x1 = xb-p
            break 

    # x2
    x2 = 0
    for p in range(limx):
        lst = []
        for y in range(len(strong)):
            if strong[y][intxb+p] == 1:
                lst.append((y, xb-p))
        if len(lst) == 0:
            x2 = xb+p
            break 

    # y1
    y1 = 0
    for p in range(limy):
        lst = []
        for x in range(len(strong[0])):
            if strong[intyb-p][x] == 1:
                lst.append((intyb, x))
        if len(lst) == 0:
            y1 = yb-p
            break 

    # y2
    y2 = 0
    for p in range(limy):
        lst = []
        for x in range(len(strong[0])):
            if strong[intyb+p][x] == 1:
                lst.append((intyb, x))
        if len(lst) == 0:
            y2 = yb+p
            break 

    dx = xb - (x1 + x2) / 2
    dy = yb - (y1 + y2) / 2


    bb = x1,x2,y1,y2

    # on a obtenu la BoundingBox. On va maintenant parcourir tous les pixels de tous les masques gt et vérifier s'ils sont dans la BB.
    # on va calculer la proportion de pixel dans la bounding box et faire une moyenne par patient et on affichera le résultat avec un box plot.

    propPat = []
    propPatOk = []
    for j in range(len(masks[1][i])) :
        # print(len(masks[1][i][0]))
        # print(f"{j} : {masks[1][i][j]}")
        maskGt = masks[1][i][j]
        tot = 0
        c = 0
        for y in range(len(maskGt)):
            for x in range(len(maskGt[0])):
                if maskGt[y][x] == 1 :
                    tot+=1
                    if isInBB(bb, (y,x)) :
                        c+=1
        if tot == 0:
            tot=1
        pp = c/tot
        if pp == 0:
            bbn=True
            if x2-x1 > 5 or y2-y1 > 5 :
                bbn=False
            z.append([i, (x1, x2, y1, y2), bbn, masks[0][i], masks[1][i]])
        else:
            propPatOk.append(pp)
        propPat.append(pp)
    prop.append(np.mean(propPat))
    if propPatOk : propOk.append(np.mean(propPatOk))
print(f"Nombre de cas où ça n'a pas du tout fonctionné : {len(z)}")
print(f"Proportion d'anglobement moyen par patient pour les autre cas : {np.mean(propOk)}")
print(f"Proportion d'anglobement moyen : {np.mean(prop)}")
plt.figure(figsize=(10, 6))
plt.boxplot([prop, propOk], labels=['Tous les cas', 'Cas réussis (>0)'])
plt.ylabel("Proportion d'engloberment")
plt.title("Boxplot des proportions d'engloberment par patient")
plt.grid(True)
plt.show()


# Avant filtrage :
# Nombre de cas où ça n'a pas du tout fonctionné : 482
# Proportion d'anglobement moyen par patient pour les autre cas : 0.8777389413907586
# Proportion d'anglobement moyen : 0.5957957394628821        
Nombre de cas où ça n'a pas du tout fonctionné : 492
Proportion d'anglobement moyen par patient pour les autre cas : 0.8948019925646392
Proportion d'anglobement moyen : 0.594996557001177
No description has been provided for this image
In [ ]:
import numpy as np
import matplotlib.pyplot as plt

def isInBB(bb, coord):
    x1, x2, y1, y2 = bb
    l, c = coord
    return (l > y1) and (c > x1) and (c < x2) and (l < y2)

pp_all   = []  # proportions (GT dans bbox) pour toutes les images
pp_thick = []  # idem mais seulement si la bbox du patient est "épaisse" (non fine)

z = []  

for i in range(len(masks[0])):

    fltMasks = call.maskFilter(masks[0][i])              
    segMasks = (np.asarray(fltMasks) > 0.5).astype(np.uint8)
    weightedMask = segMasks.mean(axis=0)                

    H, W = weightedMask.shape
    yy, xx = np.indices((H, W))

    s  = weightedMask.sum() or 1.0
    xb = (weightedMask * xx).sum() / s
    yb = (weightedMask * yy).sum() / s

    mx     = weightedMask.max()
    strong = (weightedMask > (mx / 10))

    intxb, intyb = int(xb), int(yb)
    limx = int(min(W - xb, xb))
    limy = int(min(H - yb, yb))

    # x1
    x1 = 0
    for p in range(limx):
        lst = []
        for y in range(H):
            if strong[y][intxb - p] == 1:
                lst.append((y, xb - p))
        if len(lst) == 0:
            x1 = xb - p
            break

    # x2
    x2 = 0
    for p in range(limx):
        lst = []
        for y in range(H):
            if strong[y][intxb + p] == 1:
                lst.append((y, xb - p))
        if len(lst) == 0:
            x2 = xb + p
            break

    # y1
    y1 = 0
    for p in range(limy):
        lst = []
        for x in range(W):
            if strong[intyb - p][x] == 1:
                lst.append((intyb, x))
        if len(lst) == 0:
            y1 = yb - p
            break

    # y2
    y2 = 0
    for p in range(limy):
        lst = []
        for x in range(W):
            if strong[intyb + p][x] == 1:
                lst.append((intyb, x))
        if len(lst) == 0:
            y2 = yb + p
            break

    bb = (x1, x2, y1, y2)

    is_thick = (x2 - x1 >= 2) and (y2 - y1 >= 2)

    gt_stack = np.asarray(masks[1][i])      
    gt_bool = (gt_stack != 0)               # True sur les pixels positifs du GT

    inside_mask = (xx > x1) & (xx < x2) & (yy > y1) & (yy < y2)  

    totals = np.count_nonzero(gt_bool, axis=(1, 2))
    inside_counts = np.count_nonzero(gt_bool & inside_mask[None, :, :], axis=(1, 2))
    den = np.where(totals == 0, 1, totals)
    pp_i = inside_counts / den
    pp_all.append( np.mean(pp_i))

    if is_thick:
        pp_thick.append( np.mean(pp_i))
    else:
        if [i, bb, masks[0][i], masks[1][i]] not in z:
            z.append([i, bb, masks[0][i], masks[1][i]])

print(f"Nb de patients avec bbox fine (stockés dans z) : {len(z)}")
print(f"Moyenne (toutes images) : {np.mean(pp_all):.4f}")
if len(pp_thick) > 0:
    print(f"Moyenne (images dont la bbox patient est épaisse) : {np.mean(pp_thick):.4f}")
else:
    print("Aucune bbox 'épaisse' détectée selon le critère (>=2 px en largeur ET hauteur).")

plt.figure(figsize=(10, 6))
plt.boxplot(
    [pp_all, pp_thick],
    labels=['Toutes les images', 'Images (bbox patient épaisse)']
)
plt.ylabel("Proportion du GT contenue dans la bbox du patient (par image)")
plt.title("Évaluation par image : toutes vs bbox non dégénérées")
plt.grid(True)
plt.show()
Nb de patients avec bbox fine (stockés dans z) : 11
Moyenne (toutes images) : 0.5950
Moyenne (images dont la bbox patient est épaisse) : 0.7209
No description has been provided for this image

On va vérifier si le résultat est mieux sur uniquement les images filtrées¶

In [4]:
import numpy as np
import matplotlib.pyplot as plt

def isInBB(bb, coord):
    x1, x2, y1, y2 = bb
    l, c = coord
    return (l > y1) and (c > x1) and (c < x2) and (l < y2)

pp_all   = []
pp_thick = []
z = []

for i in range(len(masks[0])):

    preds_i = np.asarray(masks[0][i])
    gts_i   = np.asarray(masks[1][i])
    preds_f, gts_f = call.maskFilterGT([preds_i, gts_i])

    preds_f = np.asarray(preds_f)
    gts_f   = np.asarray(gts_f)

    if preds_f.size == 0 or preds_f.ndim != 3:
        continue

    segMasks = (preds_f > 0.5).astype(np.uint8)   
    weightedMask = segMasks.mean(axis=0)          

    H, W = weightedMask.shape
    yy, xx = np.indices((H, W))

    s  = weightedMask.sum() or 1.0
    xb = (weightedMask * xx).sum() / s
    yb = (weightedMask * yy).sum() / s

    mx     = weightedMask.max()
    strong = (weightedMask > (mx / 10))

    intxb, intyb = int(xb), int(yb)
    limx = int(min(W - xb, xb))
    limy = int(min(H - yb, yb))

    # x1
    x1 = 0
    for p in range(limx):
        lst = []
        for y in range(H):
            if strong[y][intxb - p] == 1:
                lst.append((y, xb - p))
        if len(lst) == 0:
            x1 = xb - p
            break

    # x2
    x2 = 0
    for p in range(limx):
        lst = []
        for y in range(H):
            if strong[y][intxb + p] == 1:
                lst.append((y, xb - p))
        if len(lst) == 0:
            x2 = xb + p
            break

    # y1
    y1 = 0
    for p in range(limy):
        lst = []
        for x in range(W):
            if strong[intyb - p][x] == 1:
                lst.append((intyb, x))
        if len(lst) == 0:
            y1 = yb - p
            break

    # y2
    y2 = 0
    for p in range(limy):
        lst = []
        for x in range(W):
            if strong[intyb + p][x] == 1:
                lst.append((intyb, x))
        if len(lst) == 0:
            y2 = yb + p
            break

    bb = (x1, x2, y1, y2)
    is_thick = (x2 - x1 >= 2) and (y2 - y1 >= 2)

    gt_stack = np.asarray(gts_f)                 
    gt_bool  = (gt_stack != 0)

    inside_mask = (xx > x1) & (xx < x2) & (yy > y1) & (yy < y2)  

    totals        = np.count_nonzero(gt_bool, axis=(1, 2))
    inside_counts = np.count_nonzero(gt_bool & inside_mask[None, :, :], axis=(1, 2))
    den = np.where(totals == 0, 1, totals)       
    pp_i = inside_counts / den                   

    pp_all.append(np.mean(pp_i))
    if is_thick:
        pp_thick.append(np.mean(pp_i))
    else:
        item = [i, bb, preds_f, gts_f]
        if item not in z:
            z.append(item)

print(f"Nb de patients avec bbox fine (stockés dans z) : {len(z)}")
print(f"Moyenne (toutes images) : {np.mean(pp_all):.4f}")
if len(pp_thick) > 0:
    print(f"Moyenne (images dont la bbox patient est épaisse) : {np.mean(pp_thick):.4f}")
else:
    print("Aucune bbox 'épaisse' détectée selon le critère (>=2 px en largeur ET hauteur).")

plt.figure(figsize=(10, 6))
plt.boxplot(
    [pp_all, pp_thick if len(pp_thick) > 0 else [np.nan]],
    labels=['Toutes les images', 'Images (bbox patient épaisse)']
)
plt.ylabel("Proportion du GT contenue dans la bbox du patient (par image)")
plt.title("Évaluation par image : toutes vs bbox non dégénérées")
plt.grid(True)
plt.show()
Nb de patients avec bbox fine (stockés dans z) : 11
Moyenne (toutes images) : 0.6126
Moyenne (images dont la bbox patient est épaisse) : 0.7422
No description has been provided for this image

Amélioration de l'algo¶

In [ ]:
import numpy as np
import matplotlib.pyplot as plt
import random as rd
import cv2

pp_all   = []
pp_thick = []
z = []

# i = rd.randint(0,len(masks[0]))
# print(i)
i=8

preds_i = np.asarray(masks[0][i])
gts_i   = np.asarray(masks[1][i])
preds_f, gts_f = call.maskFilterGT([preds_i, gts_i])

preds_f = np.asarray(preds_f)
gts_f   = np.asarray(gts_f)


segMasks = (preds_f > 0.5).astype(np.uint8)   
weightedMask = segMasks.mean(axis=0)      
  
cvrtWeightedMask = (weightedMask * 255).astype(np.uint8)

contours, _ = cv2.findContours(cvrtWeightedMask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

coords = []

for cnt in contours:
    x1, y1, w, h = cv2.boundingRect(cnt)
    coords.append((x1,y1,x1 + w,y1 + h))

print(f"Nombre de contours: {len(contours)}")  
s = []
for (x1, y1, x2, y2) in coords:
    s.append(np.sum(weightedMask[y1+1:y2, x1+1:x2]))
zone = int(np.argmax(s))


(x1, y1, x2, y2) =  coords[zone]
plt.plot([x1, x1], [y1, y2], 'r')  # gauche
plt.plot([x2, x2], [y1, y2], 'r')  # droit
plt.plot([x1, x2], [y1, y1], 'r')  # haut
plt.plot([x1, x2], [y2, y2], 'r')  # bas        
plt.imshow(cvrtWeightedMask)
plt.colorbar(label='Nombre de masques actifs')
plt.title('Weighted Mask')
plt.axis('off') 
plt.show()
Nombre de contours: 6
No description has been provided for this image

Test :

In [ ]:
import numpy as np
import matplotlib.pyplot as plt

pp_all   = []
pp_thick = []
z = []

for i in range(len(masks[0])):

    preds_i = np.asarray(masks[0][i])
    gts_i   = np.asarray(masks[1][i])
    preds_f, gts_f = call.maskFilterGT([preds_i, gts_i])

    preds_f = np.asarray(preds_f)
    gts_f   = np.asarray(gts_f)

    segMasks = (preds_f > 0.5).astype(np.uint8)   
    weightedMask = segMasks.mean(axis=0)          

    cvrtWeightedMask = (weightedMask * 255).astype(np.uint8)

    contours, _ = cv2.findContours(cvrtWeightedMask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

    coords = []

    for cnt in contours:
        x1, y1, w, h = cv2.boundingRect(cnt)
        coords.append((x1,y1,x1 + w,y1 + h))

    s = []
    for (x1, y1, x2, y2) in coords:
        s.append(np.sum(weightedMask[y1+1:y2, x1+1:x2]))
    zone = int(np.argmax(s))

    bb = coords[zone]
    x1, y1, x2, y2 = bb
    is_thick = (x2 - x1 >= 2) and (y2 - y1 >= 2)

    gt_stack = np.asarray(gts_f)                 
    gt_bool  = (gt_stack != 0)

    H, W = weightedMask.shape
    yy, xx = np.indices((H, W)) 
    inside_mask = (xx > x1) & (xx < x2) & (yy > y1) & (yy < y2)  

    totals = np.count_nonzero(gt_bool, axis=(1, 2))
    inside_counts = np.count_nonzero(gt_bool & inside_mask[None, :, :], axis=(1, 2))
    den = np.where(totals == 0, 1, totals)       
    pp_i = inside_counts / den                   

    pp_all.append(np.mean(pp_i))
    if is_thick:
        pp_thick.append(np.mean(pp_i))
    else:
        item = [i, bb, preds_f, gts_f]
        if item not in z:
            z.append(item)

print(f"Nb de patients avec bbox fine (stockés dans z) : {len(z)}")
print(f"Moyenne (toutes images) : {np.mean(pp_all):.4f}")
if len(pp_thick) > 0:
    print(f"Moyenne (images dont la bbox patient est épaisse) : {np.mean(pp_thick):.4f}")
else:
    print("Aucune bbox 'épaisse' détectée selon le critère (>=2 px en largeur ET hauteur).")

plt.figure(figsize=(10, 6))
plt.boxplot(
    [pp_all, pp_thick if len(pp_thick) > 0 else [np.nan]],
    labels=['Toutes les images', 'Images (bbox patient épaisse)']
)
plt.ylabel("Proportion du GT contenue dans la bbox du patient (par image)")
plt.title("Évaluation par image : toutes vs bbox non dégénérées")
plt.grid(True)
plt.show()
Nb de patients avec bbox fine (stockés dans z) : 0
Moyenne (toutes images) : 0.6225
Moyenne (images dont la bbox patient est épaisse) : 0.6225
No description has been provided for this image